#include "checker.h"
#include "modifier.h"

#include <sstream>
#include <string>

#define BOOST_AUTO_TEST_MAIN
#define BOOST_TEST_DYN_LINK

#include <boost/test/auto_unit_test.hpp>
#include <boost/test/test_tools.hpp>

#include <boost/assign/std/vector.hpp>

using namespace std;
using namespace boost::assign;                        

BOOST_AUTO_TEST_CASE(onlineSymmetricChecker) {
    size_t d = 2;
    FullGraph gn(d + 1, n);
    ProcessState state(&gn, &gn, d);
    VertexModifier modif(new OnlineSymmetricChecker());
    EventQueue q;
    BOOST_REQUIRE(!modif.getVertex(state, 1, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 1, q));
    BOOST_REQUIRE(modif.getVertex(state, 0, q));
    BOOST_REQUIRE(modif.getVertex(state, 2, q));
    BOOST_REQUIRE(!modif.getVertex(state, 3, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 3, q));
    BOOST_REQUIRE(modif.getVertex(state, 4, q));
}

BOOST_AUTO_TEST_CASE(simpleOnlineSymmetricCoordChecker) {
    size_t d = 2;
    FullGraph gn(d + 1, n);
    ProcessState state(&gn, &gn, d);
    VertexModifier modif(new OnlineSymmetricCoordChecker());
    EventQueue q;
    BOOST_REQUIRE(modif.getVertex(state, 0, q));
    BOOST_REQUIRE(!modif.getVertex(state, 2, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 2, q));
    BOOST_REQUIRE(modif.getVertex(state, 1, q));
    BOOST_REQUIRE(modif.getVertex(state, 7, q));
    BOOST_REQUIRE(!modif.getVertex(state, 8, q));
}

BOOST_AUTO_TEST_CASE(simpleOnlineSymmetricCoordChecker2) {
    size_t d = 2;
    FullGraph gn(d + 1, n);
    ProcessState state(&gn, &gn, d);
    VertexModifier modif(new OnlineSymmetricCoordChecker());
    EventQueue q;
    BOOST_REQUIRE(modif.getVertex(state, 0, q));
    BOOST_REQUIRE(modif.getVertex(state, 7, q));
    BOOST_REQUIRE(modif.getVertex(state, 11, q));
    //0000111
    //0001011
    //0001111
    BOOST_REQUIRE(modif.getVertex(state, 15, q));
    //0011110
    BOOST_REQUIRE(!modif.getVertex(state, 30, q));
}

BOOST_AUTO_TEST_CASE(hardOnlineSymmetricCoordChecker) {
    size_t d = 2;
    FullGraph gn(d + 1, n);
    ProcessState state(&gn, &gn, d);
    VertexModifier modif(new OnlineSymmetricCoordChecker());
    EventQueue q;
    BOOST_REQUIRE(modif.getVertex(state, 0, q));
    BOOST_REQUIRE(modif.getVertex(state, 15, q));
    BOOST_REQUIRE(modif.getVertex(state, 51, q));
    // 00000000
    // 00001111
    // 00110011

    // 01010010 = 82
    BOOST_REQUIRE(!modif.getVertex(state, 82, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 82, q));
    // 01011001 = 89
    BOOST_REQUIRE(!modif.getVertex(state, 89, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 89, q));
    // 01010101 = 85 can
    BOOST_REQUIRE(modif.getVertex(state, 85, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 85, q));
    // 01010001 = 81 little ones
    BOOST_REQUIRE(!modif.getVertex(state, 81, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 81, q));
    // 01010000 = 80 little ones
    BOOST_REQUIRE(!modif.getVertex(state, 80, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 80, q));

    // 11110000 = 240 can
    BOOST_REQUIRE(modif.getVertex(state, 240, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 240, q));

    // 00111111 = 63 can
    BOOST_REQUIRE(modif.getVertex(state, 63, q));
    // 01111111 = 127 can
    BOOST_REQUIRE(modif.getVertex(state, 127, q));
}

BOOST_AUTO_TEST_CASE(finalSymmetricChecker) {
    size_t d = 2;
    FullGraph gn(d + 1, n);
    ProcessState state(&gn, &gn, d);
    VertexModifier modif(new FinalSymmetricChecker());
    EventQueue q;
    BOOST_REQUIRE(!modif.getVertex(state, 1, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 1, q));
    BOOST_REQUIRE(modif.getVertex(state, 0, q));
    BOOST_REQUIRE(modif.getVertex(state, 1, q));
    BOOST_REQUIRE(!modif.getVertex(state, 3, q));
    BOOST_REQUIRE(modif.undoGetVertex(state, 3, q));
    BOOST_REQUIRE(modif.getVertex(state, 4, q));
}

BOOST_AUTO_TEST_CASE(onlineSymmetricCheckerWorseThanFinal) {
    size_t d = 2;
    FullGraph gn(n, n);
    ProcessState state(&gn, &gn, d);
    VertexModifier modif(new OnlineSymmetricChecker());
    EventQueue q;
    BOOST_REQUIRE(modif.getVertex(state, 0, q));
    BOOST_REQUIRE(modif.getVertex(state, 1, q));
    BOOST_REQUIRE(modif.getVertex(state, 3, q));
    BOOST_REQUIRE(modif.getVertex(state, 4, q));
}
                                                    
BOOST_AUTO_TEST_CASE(SimplePotentialDegreeModifierChecker) {
    size_t d = n;
    FullGraph gn(n, n);
    ProcessState state(&gn, &gn, d);
    PotentialDegreeModifier modif;
    EventQueue q;
    BOOST_REQUIRE(!modif.notGetVertex(state, 0, q));
}

BOOST_AUTO_TEST_CASE(PotentialDegreeModifierCheckerTestEasy) {
    size_t d = 3;
    CommonGraph g(5);
    g.addEdge(0, 1);
    g.addEdge(3, 1);
    g.addEdge(4, 1);
    g.addEdge(2, 1);
    g.addEdge(2, 3);
    g.addEdge(2, 4);

    ProcessState state(&g, &g, d);
    PotentialDegreeModifier modif(2);
    VertexModifier modifv(new OkChecker());
    EventQueue q;
    for (size_t i = 0; i < 5; ++i) {
        modifv.notGetVertex(state, i, q);
        bool notRes = modif.notGetVertex(state, i, q);
        BOOST_REQUIRE(notRes == (i != 1));
        modifv.undoNotGetVertex(state, i, q);
        modif.undoNotGetVertex(state, i, q);
    }
}

BOOST_AUTO_TEST_CASE(ColorModifierCheckerTestEasy) {
    size_t d = 3;
    CommonGraph g(5);
    g.addEdge(0, 1);
    g.addEdge(3, 1);
    g.addEdge(4, 1);
    g.addEdge(2, 1);
    g.addEdge(2, 3);
    g.addEdge(2, 4);

    ProcessState state(&g, &g, d);
    ColoringModifier modif(1);
    VertexModifier modifv(new OkChecker());
    EventQueue q;
    for (size_t i = 0; i < 5; ++i) {
        modifv.notGetVertex(state, i, q);
        bool notRes = modif.notGetVertex(state, i, q);
        BOOST_REQUIRE(notRes == (i != 1 && i != 2));
        modifv.undoNotGetVertex(state, i, q);
        modif.undoNotGetVertex(state, i, q);
    }
    modifv.notGetVertex(state, 2, q);
    bool notRes = modif.notGetVertex(state, 2, q);
    BOOST_REQUIRE(!notRes);
    size_t* tmp = state.colorInfo.color;
    BOOST_REQUIRE_EQUAL(tmp[0], 0);
    BOOST_REQUIRE_EQUAL(tmp[1], 1);
    BOOST_REQUIRE_EQUAL(tmp[3], 0);
    BOOST_REQUIRE_EQUAL(tmp[2], 0);

    modifv.undoNotGetVertex(state, 2, q);
    modif.undoNotGetVertex(state, 2, q);

    modifv.notGetVertex(state, 1, q);
    notRes = modif.notGetVertex(state, 1, q);
    BOOST_REQUIRE(!notRes);
    tmp = state.colorInfo.color;
    BOOST_REQUIRE_EQUAL(tmp[0], 0);
    BOOST_REQUIRE_EQUAL(tmp[2], 0);
    BOOST_REQUIRE_EQUAL(tmp[3], 1);
    BOOST_REQUIRE_EQUAL(tmp[4], 1);
}

BOOST_AUTO_TEST_CASE(ColorModifierCheckerTestMoreComplex) {
    size_t d = 3;
    CommonGraph g(5);
    g.addEdge(0, 1);
    g.addEdge(3, 1);
    g.addEdge(4, 1);
    g.addEdge(2, 1);
    g.addEdge(2, 3);
    g.addEdge(2, 4);

    ProcessState state(&g, &g, d);
    ColoringModifier modif(0);
    VertexModifier modifv(new OkChecker());
    EventQueue q;
    for (size_t iter = 0; iter < 10; ++iter) {
        for (size_t i = 0; i < 5; ++i) if (i != 1) {
            modifv.notGetVertex(state, i, q);
            bool notRes = modif.notGetVertex(state, i, q);
            BOOST_REQUIRE(notRes == (i != 4));
        }
        for (size_t i = 0; i < 5; ++i) if (i != 1) {
            modifv.undoNotGetVertex(state, i, q);
            modif.undoNotGetVertex(state, i, q);
        }
    }
}

BOOST_AUTO_TEST_CASE(ColorModifierCheckerTestFullGraph) {
    size_t d = 3;
    FullGraph g(d, d);

    ProcessState state(&g, &g, d);
    ColoringModifier modif(0);
    VertexModifier modifv(new OkChecker());
    EventQueue q;
    for (size_t i = 0; i < 30; ++i) {
        modifv.notGetVertex(state, i, q);
        bool notRes = modif.notGetVertex(state, i, q);
        //BOOST_REQUIRE(notRes == (i != 4));
    }
    for (size_t i = 0; i < 30; ++i) {
        modifv.undoNotGetVertex(state, i, q);
        bool notRes = modif.undoNotGetVertex(state, i, q);
        //BOOST_REQUIRE(notRes == (i != 4));
    }
}
